import { Link, Contribution } from '@brillout/docpress'
import { ProvidedBy, ConfigSpec } from '../../components'

<ConfigSpec
  env="client, server"
  providedBy={<ProvidedBy noCustomGuide={true}><code>useConfig()</code></ProvidedBy>}
  global={null}
/>

The `useConfig()` hook enables you to define <Link href="/settings#html-shell" doNotInferSectionTitle>these settings</Link> inside Vike hooks and UI components.

See also: <Link href="/head-tags" />.

## Vike hooks

You can use `useConfig()` inside any Vike hook, most notably <Link href="/data">`+data`</Link>.

```tsx
// pages/movies/+data.tsx

export { data }
export type Data = Awaited<ReturnType<typeof data>>

import type { PageContextServer } from 'vike/types'
import { useConfig } from 'vike-react/useConfig' // or vike-{vue,solid}

async function data(pageContext: PageContextServer) {
  const config = useConfig()

  const response = await fetch('https://star-wars.brillout.com/api/films.json')
  let { movies } = await response.json()

  config({
    title: `${movies.length} Star Wars Movies`,
    Head: <meta name="description" content={`List of all ${movies.length} Star Wars movies.`} />
  })

  return { movies }
}
```

> Make sure to call `useConfig()` before any `await`:
> ```ts
> async function data() {
>   const response = await fetch('https://star-wars.brillout.com/api/films.json')
>   // ❌ Doesn't work: useConfig() must be called before `await fetch()`
>   const config = useConfig()
> }
> ```

> Normally hooks can only be used inside UI components — `useConfig()` is different: it can also be used inside Vike hooks. We call it a *universal hook* (`useConfig()` is the only universal hook so far).


## UI components

You can also use `useConfig()` inside UI components.

```tsx
// pages/product/@id/+Page.tsx

import { useConfig } from 'vike-react/useConfig' // or vike-{vue,solid}
import { useData } from 'vike-react/useData' // or vike-{vue,solid}
import type { Data } from './+data'

export function Page() {
  const config = useConfig()
  const data = useData<Data>()

  // Set <head> tags
  config({
    title: data.product.name,
    // Image shown when sharing on social sites (Twitter, WhatsApp, ...)
    Head: <meta property="og:image" content={data.product.image} />
  })

  // Render UI
  return (
    <>
      <h1>{data.product.name}</h1>
      <p>{data.product.description}</p>
    </>
  )
}
```

> For Vue you can use the following:
> ```ts
> import { h } from 'vue'
> config({
>   Head: h('meta', {
>     property: 'og:image',
>     content: data.product.image
>   })
> })
> ```

> See also: <Link href="/useData" />.

#### `<Config>` & `<Head>`

For a more declarative usage, you can use the `<Config>` and `<Head>` components instead of `useConfig()`:

```tsx
// pages/product/@id/+Page.tsx

import { Config } from 'vike-react/Config' // or vike-{vue,solid}
import { Head } from 'vike-react/Head' // or vike-{vue,solid}
import { useData } from 'vike-react/useData' // or vike-{vue,solid}
import type { Data } from './+data'

export function Page() {
  const data = useData<Data>()

  // Render UI and <head> tags
  return (
    <>
      <Config title={data.product.name} />
      <Head>
        {/* Image shown when sharing on social sites (Twitter, WhatsApp, ...) */}
        <meta property="og:image" content={data.product.image} />
      </Head>
      <h1>{data.product.name}</h1>
      <p>{data.product.description}</p>
    </>
  )
}
```

> The `<Config>` and `<Head>` components are just `useConfig()` wrappers — they're only for convenience.
> The following doesn't make any difference:
> ```tsx
> import { Config } from 'vike-react/Config' // or vike-{vue,solid}// [!code --]
> import { Head } from 'vike-react/Head' // or vike-{vue,solid}// [!code --]
> import { useConfig } from 'vike-react/useConfig' // or vike-{vue,solid}// [!code ++]
> import { useData } from 'vike-react/useData' // or vike-{vue,solid}
> import type { Data } from './+data'
>
> export function Page() {
>   const data = useData<Data>()
>   const config = useConfig()// [!code ++]
>
>   config({// [!code ++]
>     title: data.product.name,// [!code ++]
>     Head: <meta property="og:image" content={data.product.image} />// [!code ++]
>   })// [!code ++]
>
>   return (
>     <>
>      <Config title={data.product.name} />// [!code --]
>      <Head>// [!code --]
>        <meta property="og:image" content={data.product.image} />// [!code --]
>      </Head>// [!code --]
>      <h1>{data.product.name}</h1>
>      <p>{data.product.description}</p>
>     </>
>   )
> }
> ```

> Unlike other frameworks, Vike doesn't implement a `<Title>` component because the title value must be a string — `<Title><b>Hello</b> World</Title>` wouldn't make sense.


#### Example: React Query

The `useConfig()` hook is especially useful when using extensions such as
[`vike-react-query`](https://github.com/vikejs/vike-react/tree/main/packages/vike-react-query#readme)
and
[`vike-react-apollo`](https://github.com/vikejs/vike-react/tree/main/packages/vike-react-apollo#readme)
that enable components to fetch data.
It enables your components to use the data they fetch to set `<head>` tags.

```tsx
import { useConfig } from 'vike-react/useConfig'
import { useSuspenseQuery } from '@tanstack/react-query'

function Movies() {
  // Fetch data
  const query = useSuspenseQuery({
    queryKey: ['movies'],
    queryFn: () => fetch('https://star-wars.brillout.com/api/films.json')
  })
  const movies = query.data

  // Set <head> tags
  const config = useConfig()
  config({
    title: `${movies.length} Star Wars Movies`, // <title>
    Head: <meta name="description" content={`List of all ${movies.length} Star Wars movies.`} />
  })

  // Render UI
  return (
    <ul>
      {movies.map(({ title }) => (
        <li>{title}</li>
      ))}
    </ul>
  )
}
```

> The `<meta name="description">` tag is only shown to bots. See the explanation in the section below <Link href="#html-streaming" />.

Or with `<Config>` and `<Head>`:

```tsx
import { Config } from 'vike-react/Config'
import { Head } from 'vike-react/Head'
import { useSuspenseQuery } from '@tanstack/react-query'

function Movies() {
  // Fetch data
  const query = useSuspenseQuery({
    queryKey: ['movies'],
    queryFn: () => fetch('https://star-wars.brillout.com/api/films.json')
  })
  const movies = query.data

  // Render UI and <head> tags
  return (
    <>
      <Config title={`${movies.length} Star Wars Movies`} />
      <Head>
        <meta name="description" content={`List of all ${movies.length} Star Wars movies.`} />
      </Head>
      <ul>
        {movies.map(({ title }) => (
          <li>{title}</li>
        ))}
      </ul>
    </>
  )
}
```

## HTML Streaming

If you use <Link href="/stream">HTML Streaming</Link> together with <Link href="#ui-components">`useConfig()` inside UI components</Link>, some `<head>` tags may be missing from the streamed HTML.

This happens when a component calls `useConfig()` after the HTML stream has already started and the whole `<head>` block has already been sent to the client — it's too late to inject additional `<head>` tags.

This might seem like an issue, but it actually isn't. See the explanation below.

#### Bots

If you use <Link href="/vike-react">`vike-react`</Link> then note that it uses [`react-streaming`](https://github.com/brillout/react-streaming) which automatically disables HTML Streaming for crawlers (e.g. Googlebot), ensuring crawlers always get all `<head>` tags. See [`react-streaming` Docs > Bots](https://github.com/brillout/react-streaming#bots).

You can use [`$ curl`](https://curl.se) to see the HTML response that bots and crawlers receive:

```bash
# What bots and crawls get: no HTML Streaming, just "classic SSR"
$ curl http://localhost:3000/movies
# What human users get: HTML Streaming
$ curl http://localhost:3000/movies -N -H "User-Agent: chrome"
```

> Consequently, `<head>` tags intended for bots (SEO, PWA settings, ...) are guaranteed to be included in the HTML. They might be missing for human users, but that isn't an issue.

#### `+title`

If `<Config title={'some-title'}>` runs after the `<head>` block has already been sent, the HTML snippet `<script>document.title = 'some-title'</script>` is injected to dynamically update the page title.

Currently, `+title` is the only setting that uses such mechanism.

> Consequently, the `<title>` tag is guaranteed to be included in the HTML for bots (see section above), while human users see an up-to-date page title.

## See also

- <Link href="/head-tags" />
